package com.freemalll.merchant.utils;

import cn.hutool.extra.spring.SpringUtil;
import com.freemalll.merchant.common.CommonEnum;
import com.freemalll.merchant.mapper.common.CommonMapper;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author songshixiong
 * @ClassName DtoDiffUtil
 * @description:
 * @date 2025年05月19日
 * @version: 1.0
 */
public class DtoDiffUtil {


    /**
     * 比较两个 DTO 的所有属性，返回差异字符串
     */
    public static String compareDtos(Object oldObj, Object newObj) {
        List<String> diffs = new ArrayList<>();
        try {
            compareObjects(oldObj, newObj, "", diffs);
        } catch (Exception e) {
            throw new RuntimeException("DTO 对比出错", e);
        }
        return String.join(";", diffs);
    }

    /**
     * 递归比较对象及其嵌套对象
     */
    private static void compareObjects(Object oldObj, Object newObj, String prefix, List<String> diffs)
            throws IllegalAccessException {
        if (oldObj == null || newObj == null) {
            return;
        }

        Class<?> clazz = oldObj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);

            String fieldName = field.getName();
            Object oldValue = field.get(oldObj);
            Object newValue = field.get(newObj);

            // 忽略 getClass() 等特殊字段
            if ("class".equals(fieldName)) continue;
            // 如果是基本类型或 String，直接比较
            if (isSimpleType(field.getType())) {
                if (!Objects.equals(oldValue, newValue)) {
                    String displayName = getDisplayName(clazz, fieldName).orElse(fieldName);
                    String changeMsg = String.format("%s：由 %s 变更为 %s",
                            displayName,
                            formatFieldValue(oldValue, field),
                            formatFieldValue(newValue, field));
                    diffs.add(changeMsg);
                }
            } else {
                // 嵌套 DTO 类型，递归比较
                compareObjects(oldValue, newValue, prefix + "." + fieldName, diffs);
            }
        }
    }

    /**
     * 格式化字段值（支持Boolean转码）
     */
    private static String formatFieldValue(Object value, Field field) {
        if (value == null) {
            return "null";
        }

        // 处理Boolean类型转码
        if (value instanceof Boolean) {
            return (Boolean) value ? "启用" : "禁用";
        }

        // 处理利息费用模型枚举
        if (field.getName().equals("interestAndFeeModel") ||
                field.getName().equals("interestAndFeeDetailModel")) {
            return CommonEnum.interestAndFeeModelType.getDescByName(value.toString());
        }

        // 其他类型保持原有格式化逻辑
        return value.toString();
    }

    /**
     * 判断是否为简单类型（可直接比较）
     */
    private static boolean isSimpleType(Class<?> clazz) {
        return clazz.isPrimitive() ||
                clazz.equals(String.class) ||
                Number.class.isAssignableFrom(clazz) ||
                clazz.equals(Boolean.class) ||
                clazz.equals(Character.class);
    }

    /**
     * 获取 @ColumnName 注解中的显示名称（自定义逻辑）
     */
    private static java.util.Optional<String> getDisplayName(Class<?> clazz, String fieldName) {
        return Arrays.stream(clazz.getDeclaredFields())
                .filter(f -> f.getName().equals(fieldName))
                .findFirst()
                .map(f -> {
                    ColumnName annotation = f.getAnnotation(ColumnName.class);
                    return annotation != null ? annotation.value() : fieldName;
                });
    }

    /**
     * 比较两个 dto 中被 @ColumnName 注解标记的字段差异
     *
     * @param original 原始对象（修改前）
     * @param modified 修改后的对象
     * @return 差异描述字符串，例如：
     * "名称: 张三 → 李四, 年龄: 25 → 30"
     */
    public static String getChangedFields(Object original, Object modified) {
        try {
            List<String> changes = new ArrayList<>();
            Field[] fields = original.getClass().getDeclaredFields();

            for (Field field : fields) {
                if (field.isAnnotationPresent(ColumnName.class)) {
                    field.setAccessible(true);
                    Object originalValue = field.get(original);
                    Object modifiedValue = field.get(modified);

                    // 判断是否发生变化
                    if (!areEqual(originalValue, modifiedValue)) {
                        //如果是客户区域限制或商户区域限制 则转一下码
                        if (field.getName().equals("customerRegionalRestrictions") || field.getName().equals("merRegionalRestrictions")) {
                            if (originalValue != null && modifiedValue != null) {
                                CommonMapper bean = SpringUtil.getBean(CommonMapper.class);
                                String[] oldValue = originalValue.toString().split(",");
                                String[] newValue = modifiedValue.toString().split(",");
                                String oldValueStr = bean.selectValueByCodeList(oldValue);
                                String newValueStr = bean.selectValueByCodeList(newValue);
                                String columnName = field.getAnnotation(ColumnName.class).value();
                                changes.add(columnName + ": 由" + oldValueStr + " 变更为 " + newValueStr);
                                continue;
                            }

                        }
                        //如果是interestFeeSupport  则需要根据枚举转码 interestAndFeeModelType
                        if (field.getName().equals("interestFeeSupport") && originalValue != null && modifiedValue != null) {
                            String columnName = field.getAnnotation(ColumnName.class).value();
                            //传入的值是逗号隔开的字符串 需要转成数组在转码并将结果拼接在一起
                            if (originalValue.toString().contains(",") || modifiedValue.toString().contains(",")) {
                                String[] originalValues = originalValue.toString().split(",");
                                String[] modifiedValues = modifiedValue.toString().split(",");
                                StringBuilder oldDescBuilder = new StringBuilder();
                                for (String value : originalValues) {
                                    oldDescBuilder.append(CommonEnum.interestAndFeeModelType.getDescByName(value)).append("、");
                                }
                                StringBuilder newDescBuilder = new StringBuilder();
                                for (String value : modifiedValues) {
                                    newDescBuilder.append(CommonEnum.interestAndFeeModelType.getDescByName(value)).append("、");
                                }
                                changes.add(columnName + ": 由" + oldDescBuilder.substring(0, oldDescBuilder.length() - 1) + " 变更为 " + newDescBuilder.substring(0, newDescBuilder.length() - 1));
                            } else {
                                changes.add(columnName + ": 由" + CommonEnum.interestAndFeeModelType.getDescByName(originalValue.toString()) + " 变更为 " +
                                        CommonEnum.interestAndFeeModelType.getDescByName(modifiedValue.toString()));
                            }
                            continue;
                        }
                        String columnName = field.getAnnotation(ColumnName.class).value();
                        String before = formatValue(originalValue);
                        String after = formatValue(modifiedValue);
                        changes.add(columnName + ": 由" + before + " 变更为 " + after);
                    }
                }
            }

            return String.join("; ", changes);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 格式化字段值
     */
    private static String formatValue(Object value) {
        if (value == null) {
            return "null";
        } else if (value instanceof BigDecimal) {
            return ((BigDecimal) value).stripTrailingZeros().toPlainString();
        } else if (value instanceof Boolean) {
            return (Boolean) value ? "是" : "否";
        } else {
            return value.toString();
        }
    }

    /**
     * 安全地判断两个值是否相等
     */
    private static boolean areEqual(Object a, Object b) {
        if (a == null && b == null) return true;
        if (a == null || b == null) return false;
        if (a instanceof BigDecimal && b instanceof BigDecimal) {
            return ((BigDecimal) a).compareTo((BigDecimal) b) == 0;
        }
        // 字符串特殊处理：判断是否为逗号分隔的字符串
        if (a instanceof String && b instanceof String) {
            String strA = (String) a;
            String strB = (String) b;

            // 只有当两个字符串都包含逗号时才做特殊处理
            if (strA.contains(",") || strB.contains(",")) {
                String[] arrA = strA.trim().isEmpty() ? new String[0] : strA.split(",");
                String[] arrB = strB.trim().isEmpty() ? new String[0] : strB.split(",");
                Arrays.sort(arrA);
                Arrays.sort(arrB);
                return Arrays.equals(arrA, arrB);
            }
        }
        return a.equals(b);
    }

}
